#include "histogramme.h"
#include <iostream>
#include "pimage.h"

using namespace std;

//Constructor creating an histogram for each color
Histogramme::Histogramme(QImage* image, e_histo typeHisto,PImage* pimage)
{
    // initialisation of all variables
    this->typeHisto = typeHisto;
    this->pimage = pimage;
    this->image = image;

    seuilMin = 127;
    seuilMax = 255;

    for(int i=0;i<256;i++){
        tabRed[i]=0;
        tabGreen[i]=0;
        tabBlue[i]=0;
        tabRGB[i]=0;
    }

    // count for each color
    for(int i = 0; i < image->width(); i++){
        for(int j = 0; j < image->height(); j++){
            //color of each pixel
            int colorPixel = image->pixel(i, j);

            //incrementation of the tab for the four components R,G,B and RGB
            tabRed[qRed(colorPixel)]++;
            tabGreen[qGreen(colorPixel)]++;
            tabBlue[qBlue(colorPixel)]++;
            tabRGB[(qRed(colorPixel)+qGreen(colorPixel)+qBlue(colorPixel))/3]++;

        }
    }

    //display the different dialog boxes or modification on the picture in accordance with the enumeration
    switch (typeHisto){

        //case of the simple display for the three histograms in a new dialog box
    case Affichage :

        ui_Histo = new  Ui_Histo::Dialog();
        QDialog* dialogHisto;
        dialogHisto = new QDialog(pimage);
        ui_Histo->setupUi(dialogHisto);
        dialogHisto->show();

        QObject::connect((QObject*) (ui_Histo->couleurComboBox),SIGNAL(currentIndexChanged(int)),
                         this, SLOT(drawHistogram()));

        drawHistogram();

        break;

        //when we want a color's egalisation
    case Egalisation :

        egalize();
        updateEgalize();

        break;

        //when we want a spread of the histograms
    case Etalement :

        spread();
        updateSpread();

        break;

        //display a new dialog box permitting to shift histograms
    case Recadrage :

        ui_HistoRecadrage = new Ui_HistoRecadrage::Recadrage();
        QDialog* dialogHistoRecadrage;
        dialogHistoRecadrage = new QDialog(pimage);
        ui_HistoRecadrage->setupUi(dialogHistoRecadrage);
        dialogHistoRecadrage->show();

        QObject::connect(ui_HistoRecadrage->slider, SIGNAL(valueChanged(int)), this, SLOT(shift(int)));
        QObject::connect(ui_HistoRecadrage->buttonBox, SIGNAL(accepted()),this, SLOT(updateShift()));
        QObject::connect(ui_HistoRecadrage->buttonBox, SIGNAL(accepted()), pimage->getCurrentDrawing(), SLOT(update()));
        QObject::connect((QObject*) (ui_HistoRecadrage->couleurComboBox),SIGNAL(currentIndexChanged(int)),
                         this, SLOT(shift(int)));

        drawHistogram();

        break;

        //display a new dialog box which 'binarise' the picture in accordance with two thresholds
    case Binarisation :

        ui_HistoBin = new Ui_HistoBinarisation::Binarisation();
        QDialog* dialogHistoBinarisation;
        dialogHistoBinarisation = new QDialog(pimage);
        ui_HistoBin->setupUi(dialogHistoBinarisation);
        dialogHistoBinarisation->show();

        QObject::connect(ui_HistoBin->seuilMin,SIGNAL(valueChanged(int)), this, SLOT(seuilMinBin(int)));
        QObject::connect(ui_HistoBin->seuilMax,SIGNAL(valueChanged(int)), this, SLOT(seuilMaxBin(int)));
        QObject::connect(ui_HistoBin->buttonBox, SIGNAL(accepted()),this, SLOT(updateBinarisation()));
        QObject::connect(ui_HistoBin->buttonBox, SIGNAL(accepted()), pimage->getCurrentDrawing(), SLOT(update()));

        drawHistogram();

    }

}


//********************************************DRAW HISTOGRAM****************************************
//function permitting to draw histograms
void Histogramme::drawHistogram(int tabParamRed[256],int tabParamGreen[256],int tabParamBlue[256],int tabParamRGB[256])
{

    int maxR = 0;
    int maxG = 0;
    int maxB = 0;
    int maxRgb = 0;

    //search of the maximum in each tab
    for (int i=0; i<256; i++){
        if (tabRed[i]>maxR) {maxR=tabRed[i];}
        if (tabGreen[i]>maxG) {maxG=tabGreen[i];}
        if (tabBlue[i]>maxB) {maxB=tabBlue[i];}
        if (tabRGB[i]>maxRgb) {maxRgb=tabRGB[i];}
    }


    //According to the enumeration we display the histograms in the corresponding box
    if(typeHisto == Affichage){

        int hauteur = (ui_Histo->graphicsView->height())  - 15;
        int largeur = (ui_Histo->graphicsView->width()) - 15;

        QGraphicsScene* scene = new QGraphicsScene(-5,-5,largeur +10,hauteur + 10); //fenetre
        ui_Histo->graphicsView->setScene(scene);

        QGraphicsScene* sceneRectangle = new QGraphicsScene(-5,-3,ui_Histo->rectangleView->width()-2, 15); //fenetre
        ui_Histo->rectangleView->setScene(sceneRectangle);

        QPen* pen;
        pen = new QPen(QColor(0,0,0,90));

        QPen* penRectangle;
        penRectangle = new QPen(QColor(0,0,0,90));

        int* tab;
        int max;
        if(ui_Histo->couleurComboBox->currentText().compare("RGB") == 0){
            tab = tabRGB;
            max = maxRgb;

        }else if(ui_Histo->couleurComboBox->currentText().compare("Rouge") == 0){
            tab = tabRed;
            max = maxR;
            pen->setColor(QColor(255,0,0,85));

        }else if(ui_Histo->couleurComboBox->currentText().compare("Bleu") == 0){
            tab = tabBlue;
            max = maxB;
            pen->setColor(QColor(0,0,255,85));

        }else{
            tab = tabGreen;
            max = maxG;
            pen->setColor(QColor(0,255,0,85));

        }

        //draw histograms for each component
        for (int i=0; i<256;i++){

            ui_Histo->graphicsView->scene()->addRect(i * largeur / 255,
                                                     hauteur - (hauteur * tab[i] / max),
                                                     largeur / 255,
                                                     hauteur * tab[i] / max, *pen);

            if(ui_Histo->couleurComboBox->currentText().compare("RGB") == 0){
                penRectangle->setColor(QColor(i,i,i));
            }else if(ui_Histo->couleurComboBox->currentText().compare("Rouge") == 0){
                penRectangle->setColor(QColor(i,0,0));
            }else if(ui_Histo->couleurComboBox->currentText().compare("Bleu") == 0){
                penRectangle->setColor(QColor(0,0,i));
            }else{
                penRectangle->setColor(QColor(0,i,0));
            }

            ui_Histo->rectangleView->scene()->addRect(i*largeur/255, 0, largeur/255, 10,*penRectangle);
        }

        ui_Histo->graphicsView->show();
        ui_Histo->rectangleView->show();

    }else if(typeHisto == Recadrage){
        if(tabParamRed != NULL){
            int hauteur = (ui_HistoRecadrage->graphicsView->height())  - 15;
            int largeur = (ui_HistoRecadrage->graphicsView->width()) - 15;

            QGraphicsScene* scene = new QGraphicsScene(-5,-5,largeur +10,hauteur + 10); //fenetre
            ui_HistoRecadrage->graphicsView->setScene(scene);

            QGraphicsScene* sceneRectangle = new QGraphicsScene(-5,-3,ui_HistoRecadrage->rectangleView->width()-2, 15); //fenetre
            ui_HistoRecadrage->rectangleView->setScene(sceneRectangle);

            QPen* pen;
            pen = new QPen(QColor(0,0,0,90));

            QPen* penRectangle;
            penRectangle = new QPen(QColor(0,0,0,90));

            int* tab;
            int max;
            if(ui_HistoRecadrage->couleurComboBox->currentText().compare("RGB") == 0){
                tab = tabParamRGB;
                max = maxRgb;

            }else if(ui_HistoRecadrage->couleurComboBox->currentText().compare("Rouge") == 0){
                tab = tabParamRed;
                max = maxR;
                pen->setColor(QColor(255,0,0,85));

            }else if(ui_HistoRecadrage->couleurComboBox->currentText().compare("Bleu") == 0){
                tab = tabParamBlue;
                max = maxB;
                pen->setColor(QColor(0,0,255,85));

            }else{
                tab = tabParamGreen;
                max = maxG;
                pen->setColor(QColor(0,255,0,85));

            }

            for (int i=0; i<256;i++){
                ui_HistoRecadrage->graphicsView->scene()->addRect(i * largeur / 255,
                                                                  hauteur - (hauteur * tab[i] / max),
                                                                  largeur / 255,
                                                                  hauteur * tab[i] / max, *pen);

                if(ui_HistoRecadrage->couleurComboBox->currentText().compare("RGB") == 0){
                    penRectangle->setColor(QColor(i,i,i));
                }else if(ui_HistoRecadrage->couleurComboBox->currentText().compare("Rouge") == 0){
                    penRectangle->setColor(QColor(i,0,0));
                }else if(ui_HistoRecadrage->couleurComboBox->currentText().compare("Bleu") == 0){
                    penRectangle->setColor(QColor(0,0,i));
                }else{
                    penRectangle->setColor(QColor(0,i,0));
                }

                ui_HistoRecadrage->rectangleView->scene()->addRect(i*largeur/255, 0, largeur/255, 10,*penRectangle);
            }

            ui_HistoRecadrage->graphicsView->show();
            ui_HistoRecadrage->rectangleView->show();
        }else{

            int hauteur = (ui_HistoRecadrage->graphicsView->height())  - 15;
            int largeur = (ui_HistoRecadrage->graphicsView->width()) - 15;

            QGraphicsScene* scene = new QGraphicsScene(-5,-5,largeur +10,hauteur + 10); //fenetre
            ui_HistoRecadrage->graphicsView->setScene(scene);

            QGraphicsScene* sceneRectangle = new QGraphicsScene(-5,-3,ui_HistoRecadrage->rectangleView->width()-2, 15); //fenetre
            ui_HistoRecadrage->rectangleView->setScene(sceneRectangle);

            QPen* pen;
            pen = new QPen(QColor(0,0,0,90));

            QPen* penRectangle;
            penRectangle = new QPen(QColor(0,0,0,90));

            int* tab;
            int max;
            if(ui_HistoRecadrage->couleurComboBox->currentText().compare("RGB") == 0){
                tab = tabRGB;
                max = maxRgb;

            }else if(ui_HistoRecadrage->couleurComboBox->currentText().compare("Rouge") == 0){
                tab = tabRed;
                max = maxR;
                pen->setColor(QColor(255,0,0,85));

            }else if(ui_HistoRecadrage->couleurComboBox->currentText().compare("Bleu") == 0){
                tab = tabBlue;
                max = maxB;
                pen->setColor(QColor(0,0,255,85));

            }else{
                tab = tabGreen;
                max = maxG;
                pen->setColor(QColor(0,255,0,85));

            }

            for (int i=0; i<256;i++){
                ui_HistoRecadrage->graphicsView->scene()->addRect(i * largeur / 255,
                                                                  hauteur - (hauteur * tab[i] / max),
                                                                  largeur / 255,
                                                                  hauteur * tab[i] / max, *pen);

                if(ui_HistoRecadrage->couleurComboBox->currentText().compare("RGB") == 0){
                    penRectangle->setColor(QColor(i,i,i));
                }else if(ui_HistoRecadrage->couleurComboBox->currentText().compare("Rouge") == 0){
                    penRectangle->setColor(QColor(i,0,0));
                }else if(ui_HistoRecadrage->couleurComboBox->currentText().compare("Bleu") == 0){
                    penRectangle->setColor(QColor(0,0,i));
                }else{
                    penRectangle->setColor(QColor(0,i,0));
                }

                ui_HistoRecadrage->rectangleView->scene()->addRect(i*largeur/255, 0, largeur/255, 10,*penRectangle);
            }

            ui_HistoRecadrage->graphicsView->show();
            ui_HistoRecadrage->rectangleView->show();
        }

    }else{
        int hauteur = (ui_HistoBin->graphicsView->height())  - 15;
        int largeur = (ui_HistoBin->graphicsView->width()) - 15;

        QGraphicsScene* scene = new QGraphicsScene(-5,-5,largeur +10,hauteur + 10); //fenetre
        ui_HistoBin->graphicsView->setScene(scene);

        QGraphicsScene* sceneRectangle = new QGraphicsScene(-5,-3,ui_HistoBin->rectangleView->width()-2, 15); //fenetre
        ui_HistoBin->rectangleView->setScene(sceneRectangle);

        QPen* pen;  
        pen = new QPen(QColor(0,0,0,90));

        QPen* penRectangle;
        penRectangle = new QPen(QColor(0,0,0,90));

        for (int i=0; i<256;i++){
            ui_HistoBin->graphicsView->scene()->addRect(i * largeur / 255,
                                                        hauteur - (hauteur * tabRGB[i] / maxRgb),
                                                        largeur / 255,
                                                        hauteur * tabRGB[i] / maxRgb, *pen);

            penRectangle->setColor(QColor(i,i,i));
            ui_HistoBin->rectangleView->scene()->addRect(i*largeur/255, 0, largeur/255, 10,*penRectangle);

        }

        ui_HistoBin->graphicsView->show();
        ui_HistoBin->rectangleView->show();

    }

}

//*************************************************EGALIZATION************************************************
//function permitting to egalize each histograms
void Histogramme::egalize(){


    tabRedCumul[0]=tabRed[0];
    tabGreenCumul[0]=tabGreen[0];
    tabBlueCumul[0]=tabBlue[0];

    //Calculation of the cumulative histograms for each color composante
    for(int i=1; i<256; i++){
        tabRedCumul[i]= tabRedCumul[i-1]+tabRed[i];
        tabGreenCumul[i]= tabGreenCumul[i-1]+tabGreen[i];
        tabBlueCumul[i]= tabBlueCumul[i-1]+tabBlue[i];
    }
}

void Histogramme::updateEgalize(){

    int redC = 0;
    int greenC = 0;
    int blueC = 0;

    //Calculation of the total of pixels in the picture
    int nbPixels = image->width() * image->height();

    //egalization
    for(int i = 0; i < image->width(); i++){
        for(int j = 0; j < image->height(); j++){
            int colorPixel = image->pixel(i, j);

            redC = 255*tabRedCumul[qRed(colorPixel)]/nbPixels;
            greenC = 255*tabGreenCumul[qGreen(colorPixel)]/nbPixels;
            blueC = 255*tabBlueCumul[qBlue(colorPixel)]/nbPixels;

            image->setPixel(i,j,qRgb(redC, greenC, blueC));

        }
    }
    pimage->updateCalque();
}

//************************************************SPREAD(ETALER)********************************************
//function permitting to spread the histograms with a marge of 0.005 percent
void Histogramme::spread(){

    int maxR = 0;
    int minR = 0;
    int maxG = 0;
    int minG = 0;
    int maxB = 0;
    int minB = 0;

    //Calculation of the total of pixels in the picture
    int nbpixels=image->width() * image->height();


    int sumpixelsRMin = 0;
    int sumpixelsGMin = 0;
    int sumpixelsBMin = 0;

    //percent of the marge to spread = 0.005
    int pourcentage = 0.005 * (nbpixels / 100);

    //Calculation of the beginnig of the each histograms with the marge of 0.01 percent
    for (int i=0; i<256; i++){

        if(sumpixelsRMin < pourcentage){
            sumpixelsRMin = sumpixelsRMin + tabRed[i];
            minR = i;
        }

        if(sumpixelsGMin < pourcentage){
            sumpixelsGMin = sumpixelsGMin + tabGreen[i];
            minG = i;
        }

        if(sumpixelsBMin < pourcentage){
            sumpixelsBMin = sumpixelsBMin + tabBlue[i];
            minB = i;
        }

    }

    int sumpixelsRMax = 0;
    int sumpixelsGMax = 0;
    int sumpixelsBMax = 0;

    //Calculation of the end of the each histograms with the marge of 0.01 percent
    for(int i=255; i>=0; i--){

        if(sumpixelsRMax < pourcentage){
            sumpixelsRMax = sumpixelsRMax + tabRed[i];
            maxR = i;
        }

        if(sumpixelsGMax < pourcentage){
            sumpixelsGMax = sumpixelsGMax + tabGreen[i];
            maxG = i;
        }

        if(sumpixelsBMax < pourcentage){
            sumpixelsBMax = sumpixelsBMax + tabBlue[i];
            maxB = i;
        }

    }

    //Calculation of the coordinate for the linear equation
    aRed = 255/(maxR-minR);
    aGreen = 255/(maxG-minG);
    aBlue = 255/(maxB-minB);

    bRed = 255-aRed*maxR;
    bGreen = 255-aGreen*maxG;
    bBlue = 255-aBlue*maxB;

}

void Histogramme::updateSpread(){

    //spread
    for(int i = 0; i < image->width(); i++){
        for(int j = 0; j < image->height(); j++){
            int colorPixel = image->pixel(i, j);

            int redEt = aRed * qRed(colorPixel) + bRed;
            int greenEt = aGreen * qGreen(colorPixel) + bGreen;
            int blueEt = aBlue * qBlue(colorPixel) + bBlue;

            image->setPixel(i,j,qRgba(redEt,greenEt,blueEt, qAlpha(colorPixel)));

        }
    }
    pimage->updateCalque();
}


//*********************************************SHIFT(RECADRAGE)**************************************
void Histogramme::shift(int luminosite){

    this->luminosite = luminosite;

        int tabRedTemp[256];
        int tabGreenTemp[256];
        int tabBlueTemp[256];
        int tabRGBTemp[256];

        for(int i=0;i<256;i++){
             tabRedTemp[i] = tabRed[i];
             tabGreenTemp[i] = tabGreen[i];
             tabBlueTemp[i] = tabBlue[i];
             tabRGBTemp[i] = tabRGB[i];
        }


        if(luminosite == 0){

        }else if(luminosite < 0){

            int lum = -luminosite;

            for(int i=0; i < 256-lum; i++){
                tabRedTemp[i]=tabRed[i+lum];
                tabGreenTemp[i]=tabGreen[i+lum];
                tabBlueTemp[i]=tabBlue[i+lum];
                tabRGBTemp[i]=tabRGB[i+lum];
            }
            for(int i=255-lum+1;i<256;i++){
                tabRedTemp[i]=0;
                tabGreenTemp[i]=0;
                tabBlueTemp[i]=0;
                tabRGBTemp[i]=0;
            }

       }else{
            for(int i=255; i>=luminosite; i--){
                tabRedTemp[i]=tabRed[i-luminosite];
                tabGreenTemp[i]=tabGreen[i-luminosite];
                tabBlueTemp[i]=tabBlue[i-luminosite];
                tabRGBTemp[i]=tabRGB[i-luminosite];
            }

            for(int i=0;i<luminosite;i++){
                tabRedTemp[i]=0;
                tabGreenTemp[i]=0;
                tabBlueTemp[i]=0;
                tabRGBTemp[i]=0;
            }
        }

       drawHistogram(tabRedTemp,tabGreenTemp,tabBlueTemp,tabRGBTemp);

}

void Histogramme::updateShift(){

    for(int i = 0; i < image->width(); i++){
        for(int j = 0; j < image->height(); j++){
            int colorPixel = image->pixel(i, j);

            redShift = min(max(qRed(colorPixel) + luminosite, 0), 255);
            greenShift = min(max(qGreen(colorPixel) + luminosite, 0), 255);
            blueShift = min(max(qBlue(colorPixel) + luminosite, 0), 255);

            if(ui_HistoRecadrage->couleurComboBox->currentText().compare("RGB")==0){
                image->setPixel(i,j,qRgba(redShift,greenShift,blueShift,qAlpha(colorPixel)));
            }else if(ui_HistoRecadrage->couleurComboBox->currentText().compare("Rouge")==0){
                image->setPixel(i,j,qRgba(redShift,qGreen(colorPixel),qBlue(colorPixel),qAlpha(colorPixel)));
            }else if(ui_HistoRecadrage->couleurComboBox->currentText().compare("Bleu")==0){
                image->setPixel(i,j,qRgba(qRed(colorPixel), qGreen(colorPixel),blueShift,qAlpha(colorPixel)));
            }else{
                image->setPixel(i,j,qRgba(qRed(colorPixel),greenShift,qBlue(colorPixel),qAlpha(colorPixel)));

            }

        }
    }
    pimage->updateCalque();
}

//********************************************'BINARIZATION'****************************************
//get back the minimum threshold
void Histogramme::seuilMinBin(int seuilMin){
    this->seuilMin = seuilMin;
}

//get back the maximum threshold
void Histogramme::seuilMaxBin(int seuilMax){
    this->seuilMax = seuilMax;
}

//do the binarization
void Histogramme::updateBinarisation(){

    for(int y = 0; y < image->height(); y++) {
        for(int x = 0; x < image->width(); x++) {
            int rgb = image->pixel(x, y);
            int gray = qGray(rgb);
            image->setPixel(x, y, qRgb(gray, gray, gray));

            if(gray>=seuilMin && gray<=seuilMax){
                image->setPixel(x, y, qRgb(255, 255, 255));
            }
            else{
                image->setPixel(x, y, qRgb(0, 0, 0));
            }
        }
    }
    pimage->updateCalque();
}
